/**
 * @author Martin Stolle
 *
 */
package android.got.tasks;

import com.google.api.client.extensions.android2.AndroidHttp;
import com.google.api.client.googleapis.auth.oauth2.draft10.GoogleAccessProtectedResource;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.tasks.Tasks;
import com.google.api.services.tasks.model.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.CheckedTextView;
import android.widget.CursorAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;


public class GotTasksActivity extends ListActivity implements OnClickListener, OnLongClickListener {
    // Object with all the task lists
    private TaskLists _taskLists;
    // list of tasks
    private List<Task> _tasks;
    // store state
    private HashMap<Integer, Boolean> _isDone = new HashMap<Integer, Boolean>();
    // store CheckTextView's and TextViews
    private HashMap<Integer, TaskRow> _tasksList = new HashMap<Integer, TaskRow>();

    TasksDBHelper _DBHelper;
    TaskCursorAdapter _cursorAdapter;

    private static final String PREF = "GoTasks2710";

    private static final int DIALOG_LIST_EDIT    = 11;
    private static final int DIALOG_MORE_ACTIONS = 12;
    private static final int DIALOG_TASKS_LIST   = 13;
    private static final int DIALOG_DELETE_LIST  = 14;

    private final static int NEW_TASK_REQUEST     = 1;
    private final static int UPDATE_TASK_REQUEST  = 2;
    private final static int GET_AUTH_TOKEN       = 3;
    private final static int HANDLE_ACCOUNT_ERR   = 4;

    private final HttpTransport _transport = AndroidHttp.newCompatibleTransport();

    Tasks _service;
    GoogleAccessProtectedResource _accessProtectedResource = new GoogleAccessProtectedResource(null);

    @Override
    public void onCreate(Bundle savedInstanceState) {
        _service = new Tasks(_transport, _accessProtectedResource, new JacksonFactory());
        _service.setKey("AIzaSyAKNBOo916K2UI64b0kYly3DO3QQsoRJUo");
        _service.setApplicationName("Got Tasks?");
        super.onCreate(savedInstanceState);

        _DBHelper = new TasksDBHelper(getApplicationContext());
        _DBHelper.getWritableDatabase();

        SharedPreferences settings = getSharedPreferences(PREF, 0);
        Boolean useGoogle = settings.getBoolean("useAccount", true);
        String accessToken = settings.getString("accessToken", null);
        if (accessToken != null) {
            _accessProtectedResource.setAccessToken(accessToken);
            OnAuthFinished();
        } else if (useGoogle && accessToken == null) {
            Intent i = new Intent(this, GoogleAccountActivity.class);
            startActivityForResult(i, GET_AUTH_TOKEN);
        }
    }
/*
    @Override
    protected void onStart() {
        super.onStart();
        // The activity is about to become visible.
    }
*/
    @Override
    protected void onResume() {
        super.onResume();
        // The activity has become visible (it is now "resumed").
    }
/*    @Override
    protected void onPause() {
        super.onPause();
        // Another activity is taking focus (this activity is about to be "paused").
    }
    @Override
    protected void onStop() {
        super.onStop();
        // The activity is no longer visible (it is now "stopped")
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // The activity is about to be destroyed.
    }
*/
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case NEW_TASK_REQUEST:
                if (resultCode == RESULT_OK) {
                    if (data != null) {
                        addNewTask(data);
                    }
                }
                break;
            case UPDATE_TASK_REQUEST:
                if (resultCode == RESULT_OK) {
                    if (data != null) {
                        updateTask(data);
                    }
                }
                break;
            case GET_AUTH_TOKEN:
                if (resultCode == RESULT_OK) {
                    setAccessToken(false);
                    OnAuthFinished();
                } else {
                    // Cannot authenticate user, either retry or start offline mode
                }
                break;
            case HANDLE_ACCOUNT_ERR:
                if (resultCode == RESULT_OK) {
                    setAccessToken(true);
                    OnAuthFinished();
                } else {
                    // Cannot authenticate user, either retry or start offline mode
                }
                break;
            }
    }

    @Override
    protected Dialog onCreateDialog(int id) {
      switch (id) {
        case DIALOG_LIST_EDIT: {
            return showUpdateListDialog();
        }
        case DIALOG_TASKS_LIST: {
            return showTaskListsDialog();
        }
        case DIALOG_MORE_ACTIONS: {
            return showMoreActionsDialog();
        }
        case DIALOG_DELETE_LIST: {
            return showDeleteListDialog();
        }
      }
      return null;
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.buttonAddNew){
            this.onAddTask(null);
            return;
        } else if (v.getId() == R.id.buttonSwitchList) {
            onBtnSwitchList();
        } else if (v.getId() == R.id.buttonRefreshList) {
            onBtnRefreshList();
        } else if (v.getId() == R.id.taskTitle) {
            TaskRow taskRow = _tasksList.get(v.getTag());
            CheckedTextView checkedView = taskRow.getTaskTitle();
            Toast.makeText(getApplicationContext(), checkedView.getText(), Toast.LENGTH_SHORT).show();
            if (checkedView != null) {
                // change the state and colors
                checkedView.toggle();
                if (checkedView.isChecked()) {
                    setCheckedView(checkedView);
                    _DBHelper.setTaskCompleted(taskRow.getID(), true);
                } else {
                    setUncheckedView(checkedView);
                    _DBHelper.setTaskCompleted(taskRow.getID(), false);
                }
                _cursorAdapter.changeCursor(_DBHelper.getTasksCursor());
                // add current state to map
                _isDone.put((Integer) v.getTag(), checkedView.isChecked());
            }
        }
    }

    @Override
    public boolean onLongClick(View v) {
        if (v.getId() != R.id.buttonAddNew){
            TaskRow taskRow = _tasksList.get(v.getTag());
            CheckedTextView ct = taskRow.getTaskTitle();
            String title = ct.getText().toString();
            for (int i = 0; i < this._tasks.size(); i++) {
               if (this._tasks.get(i).getTitle().equals(title)) {
                    onAddTask(this._tasks.get(i));
                    return true;
               }
            }
            onAddTask(null);
        }
        return false;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
        case R.id.new_list:
            showDialog(DIALOG_LIST_EDIT);
            return true;
        case R.id.delete_list:
            showDialog(DIALOG_DELETE_LIST);
            return true;
        case R.id.rename_list:
            return true;
        case R.id.clear_completed:
            return true;
        case R.id.settings:
            onSettings();
            return true;
        case R.id.about:
            onAbout();
            return true;
        case R.id.actions:
            onActions();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void addNewTask(Intent data) {
        Task task = new Task();
        Bundle b = data.getExtras();

        final String title = b.getString("taskTitle");
        final String note = b.getString("taskNote");

        task.setTitle(title);
        task.setNotes(note);

        try {
            Task result = _service.tasks.insert("@default", task).execute();
            _DBHelper.addTask(result, 1);
            _cursorAdapter.changeCursor(_DBHelper.getTasksCursor());
        } catch (IOException e) {
            handleException(e);
        }
    }

    private void updateTask(Intent data) {
        Task task = new Task();
        Bundle b = data.getExtras();

        final String ID = (String) b.get("taskID");
        final String title = b.getString("taskTitle");
        final String note = b.getString("taskNote");

        task.setId(ID);
        task.setTitle(title);
        task.setNotes(note);

        _DBHelper.updateTask(task, 1);
        _cursorAdapter.changeCursor(_DBHelper.getTasksCursor());
    }

    void setAccessToken(boolean invalidate) {
        if (invalidate == true) {
            _accessProtectedResource.setAccessToken(null);
        }
        SharedPreferences settings = getSharedPreferences(PREF, 0);
        String accessToken = settings.getString("accessToken", null);
        if (accessToken == null) {
            // TODO error message and offline mode
            return;
        }
        _accessProtectedResource.setAccessToken(accessToken);
    }

    private Dialog showUpdateListDialog() {
        LayoutInflater factory = LayoutInflater.from(this);
        final View textEntryView = factory.inflate(R.layout.task_newlist, null);
        return new AlertDialog.Builder(this)
            .setTitle(R.string.new_list)
            .setView(textEntryView)
            .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    TaskList taskList = new TaskList();
                    TextView viewNotes = (TextView) textEntryView.findViewById(R.id.editTaskListName);
                    String title = viewNotes.getText().toString();
                    taskList.setTitle(title);
                    if (!title.isEmpty()) {
                        try {
                            _service.tasklists.insert(taskList).execute();
                        } catch (IOException e) {
                            handleException(e);
                        }
                    }
                }
            })
            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    dialog.cancel();
                }
            })
            .create();
    }

    private Dialog showTaskListsDialog() {
        if (_taskLists == null) {
            _taskLists = this.getTaskLists();
            _taskLists.toString();
        }

        final CharSequence[] items = new String[_taskLists.size()-1];
        List<TaskList> allLists = _taskLists.getItems();
        for(int i = 0; i < items.length; i++) {
            items[i] = allLists.get(i).getTitle();
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setItems(items, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int item) {
                for (TaskList taskList : _taskLists.getItems()) {
                    if (taskList.getTitle().contains(items[item])) {
                        SharedPreferences settings = getSharedPreferences(PREF, 0);
                        SharedPreferences.Editor editor = settings.edit();
                        editor.putString("taskListID", taskList.getId());
                        editor.commit();
                    }
                }
            }
        });
        return builder.create();
    }

    private Dialog showMoreActionsDialog() {
        final String[] items = getResources().getStringArray(R.array.actions_list);

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.actions);
        builder.setItems(items, new DialogInterface.OnClickListener() {
            // get item that the user clicked
            public void onClick(DialogInterface dialog, int item) {
                if (item == 3)
                    new ExportDatabaseFileTask().execute();
                else
                    Toast.makeText(getApplicationContext(), items[item], Toast.LENGTH_SHORT).show();
            }
        });
       return builder.create();
       }


    private Dialog showDeleteListDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.delete_list_info)
               .setCancelable(false)
               .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                        // remove list
                   }
               })
               .setNegativeButton("No", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                        dialog.cancel();
                   }
               });
        return builder.create();
    }

    private void OnAuthFinished() {
        setContentView(R.layout.tasks_list);

        _tasks = getTasks();
        ImageButton addTaskButton = (ImageButton) findViewById(R.id.buttonAddNew);
        ImageButton switchListsButton = (ImageButton) findViewById(R.id.buttonSwitchList);
        ImageButton refreshListButton = (ImageButton) findViewById(R.id.buttonSwitchList);
        addTaskButton.setOnClickListener(this);
        switchListsButton.setOnClickListener(this);
        refreshListButton.setOnClickListener(this);

        Cursor cursor = _DBHelper.getTasksCursor();
        // Columns that will be assigned to the cursor
        String[] from = {TasksDBHelper.TASK_CLM_PK, TasksDBHelper.TASK_CLM_TITLE, TasksDBHelper.TASK_CLM_NOTES, TasksDBHelper.TASK_CLM_DUE};
        // xml defined views the data will be assigned to
        int[] to = {R.id.taskTitle, R.id.taskNotes, R.id.taskDate};
        _cursorAdapter = new TaskCursorAdapter(this, R.layout.task_row, cursor, from, to, 0);

        setListAdapter(_cursorAdapter);
    }

    public boolean onDelete() {
       // get selected tasks, if more than 1 task is selected ask user if he is sure
       return true;
    }

    public void onSearch() {
        return;
    }

    public void onAbout() {
        return;
    }

    public void onRefresh() {
        this.OnAuthFinished();
        return;
    }

    public void onActions() {
        showDialog(DIALOG_MORE_ACTIONS);
    }

    private void onBtnRefreshList() {
        OnAuthFinished();
    }

    private void onBtnSwitchList() {
        showDialog(DIALOG_TASKS_LIST);
    }
    

    public void onAddTask(Task curTask) {
        Intent i = new Intent(this, TasksAdder.class);
        if (curTask == null) {
            startActivityForResult(i, NEW_TASK_REQUEST);
        } else {
            i.putExtra("taskTitle", curTask.getTitle());
            i.putExtra("taskNote", curTask.getNotes());
            // Compile and use regular expression
            if (curTask.getDue() != null) {
                String date = curTask.getDue().toString();
                Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
                Matcher m = pattern.matcher(date);
                if (m.find()) {
                  int year   = Integer.parseInt(m.group(1));
                  int month = Integer.parseInt(m.group(2));
                  int day  = Integer.parseInt(m.group(3));
                  i.putExtra("dueDay", day);
                  i.putExtra("dueMonth", month);
                  i.putExtra("dueYear", year);
                }
            }
            startActivityForResult(i, UPDATE_TASK_REQUEST);
        }
    }

    public void onSettings() {
        // TODO use preferences class of android
        Intent i = new Intent(this, TaskSettings.class);
        startActivity(i);
    }

    private List<Task> getTasks() {
        List<Task> tasks = null;
        try {
            SharedPreferences settings = getSharedPreferences(PREF, 0);
            String taskListID = settings.getString("taskListID", null);
            if (taskListID == null) {
                tasks = _service.tasks.list("@default").execute().getItems();
                SharedPreferences.Editor editor = settings.edit();
                editor.putString("taskListID", "@default");
                editor.commit();
            } else {
                com.google.api.services.tasks.model.Tasks ts = _service.tasks.list(taskListID).execute();

                _DBHelper.updateTasksDB(ts, 1);
                tasks = ts.getItems(); 
            }
            return tasks;
        } catch (IOException e) {
            handleException(e);
        }
        return tasks;
    }

    private TaskLists getTaskLists() {
        TaskLists taskLists = null;
        try {
            taskLists = _service.tasklists.list().execute();
        } catch (IOException e) {
            handleException(e);
        }
        return taskLists;
    }

    public class TaskCursorAdapter extends CursorAdapter {

        public TaskCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
            super(context, c);
        }

        @Override
        public View newView(Context context, Cursor cur, ViewGroup parent) {
            LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            return vi.inflate(R.layout.task_row, null);
        }

        @Override
        public void bindView(View view, Context context, Cursor cur) {
            CheckedTextView viewTitle = (CheckedTextView) view.findViewById(R.id.taskTitle);
            TextView viewNotes = (TextView) view.findViewById(R.id.taskNotes);
            TextView viewDue = (TextView) view.findViewById(R.id.taskDate);

            final int pos = cur.getPosition();

            final String id = cur.getString(cur.getColumnIndex(TasksDBHelper.TASK_CLM_ID));
            final String title = cur.getString(cur.getColumnIndex(TasksDBHelper.TASK_CLM_TITLE));
            final String notes = cur.getString(cur.getColumnIndex(TasksDBHelper.TASK_CLM_NOTES));
            final String status = cur.getString(cur.getColumnIndex(TasksDBHelper.TASK_CLM_STATUS));

            if (id !=  null) {
                if (status != null && _isDone.get(pos) == null) {
                    _isDone.put(pos, status.equals(TasksDBHelper.TASK_COMPL));
                } else if (_isDone.get(pos) == null){
                    _isDone.put(pos, false);
                }
            } else {
                return;
            }

            if (title != null && title.length() > 0) {
                viewTitle.setText(title);
                // toggle visibility for notes
                if (notes != null && notes.length() > 0) {
                    viewNotes.setVisibility(TextView.VISIBLE);
                    viewNotes.setText(notes);
                } else {
                    viewNotes.setVisibility(TextView.GONE);
                }

                // toggle visibility for due date
                String dueDate = cur.getString(cur.getColumnIndex(TasksDBHelper.TASK_CLM_DUE));
                if (dueDate != null && dueDate.length() > 0) {
                    dueDate = Utils.getNormalizedDate(dueDate);
                    viewDue.setText(dueDate);
                    viewDue.setVisibility(TextView.VISIBLE);
                } else {
                    viewDue.setVisibility(TextView.GONE);
                }

                // Set completed status of entry
                if (_isDone.get(pos) != null && _isDone.get(pos)) {
                    viewTitle.setChecked(true);
                    setCheckedView(viewTitle);
                } else { // status = needsAction, because we only have these two
                    viewTitle.setChecked(false);
                    setUncheckedView(viewTitle);
                }

                // tag it - used when clicked upon to change state
                viewTitle.setTag(pos);
                _tasksList.put(pos, new TaskRow(viewTitle, viewNotes, viewDue, id));

                // set click listener for this item
                viewTitle.setOnClickListener(GotTasksActivity.this);
                viewTitle.setOnLongClickListener(GotTasksActivity.this);
            }

        }

    }

    void setCheckedView(final CheckedTextView viewTitle) {
        viewTitle.setTextColor(Color.GRAY);
        viewTitle.setPaintFlags(viewTitle.getPaintFlags() | 
                                Paint.STRIKE_THRU_TEXT_FLAG | 
                                Paint.ANTI_ALIAS_FLAG);
    }

    void setUncheckedView(final CheckedTextView viewTitle) {
        viewTitle.setPaintFlags(android.R.attr.textAppearanceLarge | Paint.ANTI_ALIAS_FLAG);
        viewTitle.setTextColor(Color.BLACK);
    }

    void handleException(Exception e) {
        if (e instanceof HttpResponseException) {
            HttpResponse response = ((HttpResponseException) e).getResponse();
            int statusCode = response.getStatusCode();
            try {
                response.ignore();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            if (statusCode == 401) {
               Intent i = new Intent(this, GoogleAccountActivity.class);
               i.putExtra("ErrorCode", 401);
               startActivityForResult(i, HANDLE_ACCOUNT_ERR);
               return;
            } else if (statusCode == 412) {
                Toast.makeText(getApplicationContext(), response.getStatusMessage(), Toast.LENGTH_LONG).show();
                return;
            } else {
                Toast.makeText(getApplicationContext(), response.getStatusMessage(), Toast.LENGTH_LONG).show();
            }
        }
    }

}